from fastapi import Depends
from jwt import PyJWTError
from core.database import DBSession
from core.exception.errors import ErrorException, TokenError, TokenExpired, AuthorizationError
from core.security import OAuth2
from pydantic import ValidationError
import jwt
from conf.config import app_config, jwt_config
from crud.admin_cruds.group_crud import curd_admin_group
from crud.admin_cruds.user_crud import curd_admin_user
from models import AdminUser
from fastapi import Request


# 记录路由函数的权限和模块信息
permission_meta_infos = {}


async def get_current_user(request: Request, db: DBSession, token: str = Depends(OAuth2)) -> AdminUser:
    """
    通过token获取当前用户
    :param request:
    :param db: DBSession
    :param token:
    :return:
    """
    try:
        # 解密token
        payload = jwt.decode(token, app_config.SECRET_KEY, algorithms=[jwt_config.ALGORITHM])
        # 用户id
        user_id = payload.get("user_id")
        current_user = await curd_admin_user.get_row(key="id", value=user_id)
        if not current_user:
            raise ErrorException("用户不存在")
        if not current_user.is_active:
            raise ErrorException("用户未激活")
        request.state.user = current_user
        return current_user

    except jwt.ExpiredSignatureError:
        raise TokenExpired()

    except jwt.InvalidTokenError:
        raise TokenError()

    except (PyJWTError, ValidationError):
        raise TokenError()


def check_permission(model_name, func_name):
    if model_name not in permission_meta_infos.keys():
        permission_meta_infos[model_name] = []
    permission_meta_infos[model_name].append(func_name)

    async def _check_permission(request: Request, current_user=Depends(get_current_user)):
        async def check_logic():
            if not current_user.group_id:
                raise ErrorException("用户未分配分组")
            group = await curd_admin_group.get(pk=current_user.group_id)
            if not group:
                raise ErrorException("用户分组不存在")
            user_scopes = group.roles
            # 权限校验
            if f'{model_name}.{func_name}' not in user_scopes:
                raise AuthorizationError

            # 缓存用户权限
            request.state.user_scopes = user_scopes
            # 缓存用户ID
            request.state.user_id = current_user.id

        await check_logic()
    return _check_permission
